﻿//using System;

#region USING
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using BrickBreaker.Core;
using Microsoft.Xna.Framework.Input;

using Hud;
using System.Collections.Generic;
using System;
#endregion USING

namespace BrickBreaker.Gameplay
{
    public class BBClassicLevels : BBLevelStencil
    {
        #region DATA MEMBERS

        // Used to track when the multiplier powerup is active
        private bool multiplierActive = false;
        string levelFilePath = "";

        #endregion

        #region OBJECT CONSTRUCTION
        //
        //public BBClassicLevel1()
        public BBClassicLevels(string levelFilePath)
        {
            isPaused = false;
            checkCollision = false;
            this.levelFilePath = levelFilePath;
        }
        //
        #endregion OBJECT CONSTRUCTION

        /// <summary>
        /// Loads all the content (Assets, Fonts, Sound, etc.)
        /// </summary>
        public override void LoadContent()
        {
            base.background1 = new BBBackground(BBGlobalConfig.background_ice01);
            base.track = new BBBackground(BBGlobalConfig.paddle_track);
            base.track.Position = new Vector2(0.0f, 510.0f);

            base.paddle = new BBPaddle(BBGlobalConfig.paddle_ball);
            base.bullets = new List<BBProjectile>();

            //Add the first ball
            base.balls = new List<BBBall>();
            BBBall ball = new BBBall(BBGlobalConfig.bbball_green, Vector2.Zero);
            ball.IsPrimaryBall = true;
            base.balls.Add(ball);

            //Add the Bricks
            base.bricks = new BBBrickManager();
            base.bricks.GenerateBricks(BBBrickManager.ConvertUML2Bricks(levelFilePath));

            BBGlobalConfig.powerupManager.UnlockNewPowerUp(PowerType.LONG);
            BBGlobalConfig.powerupManager.UnlockNewPowerUp(PowerType.SHORT);
            BBGlobalConfig.powerupManager.UnlockNewPowerUp(PowerType.SPLIT);
            BBGlobalConfig.powerupManager.UnlockNewPowerUp(PowerType.DOUBLE_SHOOT);
            BBGlobalConfig.powerupManager.UnlockNewPowerUp(PowerType.NORMAL);
        }

        #region DO_NOT_USE
        /// <summary>
        /// MAYBE USED IN FUTURE - Unloads all the content. Releases the memory back to the buffer.
        /// </summary>
        public override void UnloadContent()
        {
            //what goes here???
            //default game asset(s) unload...
        }
        //
        #endregion DO_NOT_USE

        /// <summary>
        /// Updates the level's game world objects.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            if (BBGlobalConfig.hud.TimeReached)
            {
                BBGlobalConfig.hud.TimeReached = false;
                multiplierActive = false;
                bricks.ResetBrickScore(bricks.Multiplier);
                bricks.Multiplier = 1;
            }

            #region BALL IS DEAD

            List<BBBall> ballList = new List<BBBall>();

            foreach (BBBall ball in balls)
            {
                //Player Missed Hitting the Ball - DEAD STATE
                if (ball.Position.Y + ball.Size.Y > BBGlobalConfig.getWindowHeight())
                {
                    if (balls.Count == 1)
                    {
                        BBGlobalConfig.SetVolume(1.0f);
                        BBGlobalConfig.DyingSound.Play();

                        //Subtract Player Life, etc..
                        BBGlobalConfig.hud.Lives--;

                        Reset();

                        //BBGlobalConfig.powerupManager.UnlockNewPowerUp();

                        break;
                    }
                    else
                    {
                        ballList.Add(ball);
                    }
                }
            }

            for (int i = 0; i < ballList.Count; i++)
            {
                balls.Remove(ballList[i]);
            }

            #endregion BALL IS DEAD

            paddle.Move(gameTime);
            //
            if (!balls[0].CanLaunch)
            {
                balls[0].Position = new Vector2(paddle.Position.X + ((paddle.Size.X / 2) - (balls[0].Size.X / 2)), paddle.Position.Y - (balls[0].Size.Y));

                #region CHECK IF BALL IS LAUNCHED

                if (BBGlobalConfig.keyboard.Spacebar)
                {
                    BBGlobalConfig.SetVolume(1f);
                    BBGlobalConfig.BallLaunchSound.Play();

                    // switch to the normal paddle
                    paddle.Type = PaddleType.NORMAL;

                    // THEN set the ball's position relative to the new paddle
                    balls[0].Position = new Vector2(paddle.Position.X + ((paddle.Size.X / 2) - (balls[0].Size.X / 2)), paddle.Position.Y - (balls[0].Size.Y));

                    balls[0].CanLaunch = true;
                    checkCollision = true;
                }
                #endregion
            }
            else
            {
                if (paddle.Type == PaddleType.SINGLE_SHOOT || paddle.Type == PaddleType.DOUBLE_SHOOT)
                {
                    #region CREATE BULLETS

                    BBGlobalConfig.keyboard.KeyPressedState = PressedState.SINGLE_PRESS;

                    if (BBGlobalConfig.hud.Ammo > 0)
                    {
                        if (BBGlobalConfig.keyboard.Spacebar)
                        {
                            BBGlobalConfig.SetVolume(.05f);
                            BBGlobalConfig.ShootingSound1.Play();

                            if (paddle.Type == PaddleType.SINGLE_SHOOT)
                            {
                                Vector2 pos = paddle.Position;
                                pos.X += (paddle.Size.X / 2) - 5;

                                BBProjectile bullet = new BBProjectile(pos);

                                bullets.Add(bullet);
                                BBGlobalConfig.hud.Ammo -= 1;
                            }
                            else
                            {
                                // create 2 bullets
                                for (int i = 0; i < 2; i++)
                                {
                                    if (i == 0)
                                    {
                                        Vector2 pos = paddle.Position;
                                        pos.X += (paddle.Size.X / 5) + 5;

                                        BBProjectile bullet = new BBProjectile(pos);
                                        bullets.Add(bullet);

                                    }
                                    else
                                    {
                                        Vector2 pos = paddle.Position;
                                        pos.X += (paddle.Size.X - (paddle.Size.X / 5) - 10);

                                        BBProjectile bullet = new BBProjectile(pos);
                                        bullets.Add(bullet);
                                    }
                                }

                                BBGlobalConfig.hud.Ammo -= 1;
                            }
                        }
                    }
                    #endregion

                    else { paddle.Type = PaddleType.NORMAL; }
                }
            }

            foreach (BBProjectile bullet in bullets)
            {
                bullet.Move(gameTime);
            }

            foreach (BBBall ball in balls)
            {
                ball.Move(gameTime);
            }

            if (checkCollision)
            {
                #region CHECK BALL / PADDLE COLLISION
                //
                foreach (BBBall ball in balls)
                {
                    if (paddle.Intersects(ball.getRectBounds())) //Box Collision Check
                    {
                        if (paddle.hasCollided(ball)) //Thorough Collision Check
                        {
                            //Check to make sure Ball is NOT trapped inside Paddle sprite
                            ////if (paddle.IsBallTrappedInPaddle)
                            ////{
                            ////    ball.Position = paddle.AdjPos_BallTrappedInPaddle;
                            ////}

                            //Check to make sure Paddle->ComplexCollision happens ONCE
                            if (!paddle.HasRegisteredCollision)
                            {
                                Vector2 reflectionVector2 = paddle.ComplexCollision(ball);
                                ball.Reflect(reflectionVector2);
                                BBGlobalConfig.PaddleCollisionSound.Play();
                            }
                        }
                    }
                }
                #endregion CHECK BALL / PADDLE COLLISION


                #region CHECK BALL / BRICK
                //
                BBGlobalConfig.SetVolume(.05f);

                foreach (BBBall ball in balls)
                {
                    if (bricks.hasCollided(ball))
                    {
                        // IF ACTUALLY DESTROYED
                        if (bricks.GetHitBrick().Density != BrickDensity.SOLID && bricks.GetHitBrick().HitCount == 0)
                        {
                            #region DECIDE IF POWERUP IS DROPPED

                            BBPowerup powerUp = BBGlobalConfig.powerupManager.GetAvailablePowerUp();

                            if (powerUp != null)
                            {
                                if (powerUp.Type != PowerType.NONE)
                                {
                                    powerUp.Position = bricks.GetBrickPosition();
                                    powerUp.Position -= powerUp.Size / 2;
                                    // store ^ in a list of powerups and use that list to update/ draw all powerups
                                    BBGlobalConfig.powerupManager.AddPowerUp(powerUp);
                                }
                            }
                            #endregion

                            #region UPDATE HUD: SCORE AND BRICK COUNT

                            BBGlobalConfig.SetVolume(.05f);
                            BBGlobalConfig.BrickDestroyedSound.Play();

                            BBGlobalConfig.hud.BrickCount = bricks.BricksLeft;
                            BBGlobalConfig.hud.Score += bricks.GetHitBrick().ScoreValue;

                            #endregion
                        }
                        else
                        {
                            BBGlobalConfig.SetVolume(.05f);
                            BBGlobalConfig.BrickHitSound.Play();
                        }
                        if (!bricks.HasRegisteredCollision)
                        {
                            ball.Reflect(bricks.ComplexCollision(ball));
                        }
                    }
                }
                //
                #endregion CHECK BALL / BRICK


                #region CHECK AMMO / BRICK

                List<BBProjectile> tempList = new List<BBProjectile>();

                foreach (BBProjectile bullet in bullets)
                {
                    if (bricks.hasCollided(bullet))
                    {
                        tempList.Add(bullet);

                        // IF ACTUALLY DESTROYED
                        if (bricks.GetHitBrick().Density != BrickDensity.SOLID && bricks.GetHitBrick().HitCount == 0)
                        {
                            #region DECIDE IF POWERUP IS DROPPED

                            BBPowerup powerUp = BBGlobalConfig.powerupManager.GetAvailablePowerUp();

                            if (powerUp != null)
                            {
                                if (powerUp.Type != PowerType.NONE)
                                {
                                    powerUp.Position = bricks.GetBrickPosition();
                                    powerUp.Position -= powerUp.Size / 2;
                                    // store ^ in a list of powerups and use that list to update/ draw all powerups
                                    BBGlobalConfig.powerupManager.AddPowerUp(powerUp);
                                }
                            }
                            #endregion

                            #region UPDATE HUD: SCORE AND BRICK COUNT

                            BBGlobalConfig.SetVolume(.05f);
                            BBGlobalConfig.BrickDestroyedSound.Play();

                            BBGlobalConfig.hud.BrickCount = bricks.BricksLeft;
                            BBGlobalConfig.hud.Score += bricks.GetHitBrick().ScoreValue;

                            #endregion
                        }
                        else
                        {
                            if (!bricks.HasRegisteredCollision)
                            {
                                BBGlobalConfig.SetVolume(.05f);
                                BBGlobalConfig.BrickHitSound.Play();
                            }
                        }
                    }
                }

                foreach (BBProjectile bullet in tempList)
                {
                    bullets.Remove(bullet);
                }

                #endregion

                bricks.Update();

                //update powerups within powerupMgr
                BBGlobalConfig.powerupManager.Update();

                #region CHECK PADDLE / POWERUP

                if (BBGlobalConfig.powerupManager.caughtByPaddle(paddle))
                {
                    PowerUp power = BBGlobalConfig.powerupManager.getCaughtPowerup();

                    if (power.PowerUpType == PowerType.SPLIT && balls.Count > 9)
                    {
                        power.PowerUpType = PowerType.NONE;
                    }
                    if (power.PowerUpType != PowerType.NONE)
                    {
                        BBGlobalConfig.SetVolume(1.0f);
                        BBGlobalConfig.CollectPowerupSound.Play();

                        #region PADDLE POWERUPS

                        if (power.GameObject == PowerUpObject.PADDLE)
                        {
                            paddle.Type = (PaddleType)power.PowerUpType;
                        }

                        #endregion

                        #region BALL POWERUPS

                        else if (power.GameObject == PowerUpObject.BALL)
                        {
                            #region SPEED UP POWERUP

                            if (power.PowerUpType == PowerType.FAST)
                            {
                                foreach (BBBall ball in balls)
                                {
                                    ball.Speed = new Vector2(ball.Speed.X + 1.0f);
                                }
                            }
                            #endregion

                            #region SLOW DOWN POWERUP

                            else if (power.PowerUpType == PowerType.SLOW)
                            {
                                foreach (BBBall ball in balls)
                                {
                                    ball.Speed = new Vector2(ball.Speed.X - 0.5f);
                                }
                            }
                            #endregion

                            #region SPLIT BALL

                            else if (power.PowerUpType == PowerType.SPLIT)
                            {
                                List<BBBall> temp = new List<BBBall>();

                                int seed = 0;

                                // Each existing ball in the world
                                foreach (BBBall b in balls)
                                {
                                    seed++;

                                    // Create 2 balls relative to each existing ball
                                    for (int i = 0; i < 2; i++)
                                    {
                                        float radians;
                                        Random rand = new Random(seed);
                                        int index = rand.Next(1, 9);

                                        radians = (float)Math.Atan2(b.Direction.Y, b.Direction.X);

                                        if (i % 2 == 0)
                                        {
                                            BBBall ball = new BBBall(BBGlobalConfig.bbball_green, b.Position);
                                            ball.Texture = ball.DecideTexture(index);

                                            radians += MathHelper.ToRadians(15.0f);

                                            Vector2 tempDirection = new Vector2((float)Math.Cos(radians),
                                                                            (float)Math.Sin(radians));

                                            ball.Direction = tempDirection;
                                            //
                                            ball.CanLaunch = true;
                                            temp.Add(ball);
                                        }
                                        else
                                        {
                                            BBBall ball = new BBBall(BBGlobalConfig.bbball_green, b.Position);
                                            ball.Texture = ball.DecideTexture(index);

                                            radians -= MathHelper.ToRadians(15.0f);

                                            Vector2 tempDirection = new Vector2((float)Math.Cos(radians),
                                                                            (float)Math.Sin(radians));

                                            ball.Direction = tempDirection;
                                            //
                                            ball.CanLaunch = true;
                                            temp.Add(ball);
                                        }
                                    }
                                }

                                // had to add them to a temp list then add them to the list, because you can't modify the list while looping through the list.
                                for (int i = 0; i < temp.Count; i++)
                                {
                                    if (balls.Count < 9)
                                    {
                                        balls.Add(temp[i]);
                                    }
                                }
                            }
                            #endregion

                            #region BOMB BALL

                            else if (power.PowerUpType == PowerType.BOMB)
                            {
                                // set up bomb code here
                            }

                            #endregion
                        }


                        #endregion

                        #region SCORE POWERUPS

                        else if (power.GameObject == PowerUpObject.SCORE)
                        {
                            // set back to false when "Time" runs out for the multiplier bonus
                            if (!multiplierActive)
                            {
                                if (power.PowerUpType == PowerType.MULTIPLIER_2X)
                                {
                                    bricks.Multiplier = 2;
                                    multiplierActive = true;
                                }
                                else if (power.PowerUpType == PowerType.MULTIPLIER_4X)
                                {
                                    bricks.Multiplier = 4;
                                    multiplierActive = true;
                                }

                                BBGlobalConfig.hud.StartTimer(30.0f);
                            }
                        }
                        #endregion
                    }
                }

                #endregion

            } //Do Collision Check ONLY once ball is launched
        }

        /// <summary>
        /// Draws all the levels game world objects.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Draw(SpriteBatch spriteBatch)
        {
            background1.Draw(spriteBatch);

            track.Draw(spriteBatch);

            bricks.Draw(spriteBatch);
            //
            BBGlobalConfig.powerupManager.Draw(spriteBatch);
            //
            foreach (BBBall ball in balls)
            {
                ball.Draw(spriteBatch);     //draw the balls
            }

            paddle.Draw(spriteBatch);   //draw the paddle

            foreach (BBProjectile bullet in bullets)
            {
                bullet.Draw(spriteBatch);
            }
        }

        /// <summary>
        /// Resets the level and it's game world objects.
        /// </summary>
        public override void Reset()
        {
            //Reset paddle and other default game state, objects, etc here...
            checkCollision = false;

            // destroy all existing balls
            //while (balls.Count != 0)
            //{
            //    int index = balls.Count - 1;

            //    balls.Remove(balls[index]);
            //}

            balls.Clear();

            //foreach (BBBall ball in balls)
            //{
            //    ball.Reset();
            //}

            BBBall ball = new BBBall(BBGlobalConfig.bbball_green, Vector2.Zero);
            ball.IsPrimaryBall = true;
            balls.Add(ball);

            paddle.Reset();

            bullets.Clear();

            BBGlobalConfig.powerupManager.Reset();
        }

    }//end class
}//end namespace
